﻿using System;
using System.Collections.Generic;
using System.Text;

namespace ArgusLib.Threading.Collections
{
	public interface ISynchronizedDictionary<TKey, TValue>
		: ISynchronizedCollection<KeyValuePair<TKey,TValue>>, IDictionary<TKey,TValue>
	{
		ISynchronizedCollection<TKey> Keys { get; }
		ISynchronizedCollection<TValue> Values { get; }
	}

	public abstract class SynchronizedDictionaryBase<TKey, TValue>
		: SynchronizedCollectionBase<KeyValuePair<TKey,TValue>>, ISynchronizedDictionary<TKey, TValue>
	{
		public SynchronizedDictionaryBase()
			: base() { }

		public SynchronizedDictionaryBase(object syncRoot)
			: base(syncRoot) { }

		protected abstract ISynchronizedCollection<TKey> KeysGetCore();
		ISynchronizedCollection<TKey> ISynchronizedDictionary<TKey, TValue>.Keys
		{
			get
			{
				ISynchronizedCollection<TKey> keys = this.KeysGetCore();
				if (keys.SyncRoot != this.SyncRoot)
					throw new InvalidSyncRootException();
				return keys;
			}
		}
		ICollection<TKey> IDictionary<TKey, TValue>.Keys { get { return ((ISynchronizedDictionary<TKey, TValue>)this).Keys; } }

		protected abstract ISynchronizedCollection<TValue> ValuesGetCore();
		ISynchronizedCollection<TValue> ISynchronizedDictionary<TKey, TValue>.Values
		{
			get
			{
				ISynchronizedCollection<TValue> values = this.ValuesGetCore();
				if (values.SyncRoot != this.SyncRoot)
					throw new InvalidSyncRootException();
				return values;
			}
		}
		ICollection<TValue> IDictionary<TKey, TValue>.Values { get { return ((ISynchronizedDictionary<TKey, TValue>)this).Values; } }

		protected abstract TValue ItemGetCore(TKey key);
		protected abstract void ItemSetCore(TKey key, TValue value);
		TValue IDictionary<TKey, TValue>.this[TKey key]
		{
			get { lock (this.SyncRoot) { return this.ItemGetCore(key); } }
			set { lock (this.SyncRoot) { this.ItemSetCore(key, value); } }
		}

		protected abstract void AddCore(TKey key, TValue value);
		void IDictionary<TKey, TValue>.Add(TKey key, TValue value) { lock (this.SyncRoot) { this.AddCore(key, value); } }

		protected abstract bool RemoveCore(TKey key);
		bool IDictionary<TKey, TValue>.Remove(TKey key) { lock (this.SyncRoot) { return this.RemoveCore(key); } }

		protected abstract bool ContainsKeyCore(TKey key);
		bool IDictionary<TKey, TValue>.ContainsKey(TKey key) { lock (this.SyncRoot) { return this.ContainsKeyCore(key); } }

		protected abstract bool TryGetValueCore(TKey key, out TValue value);
		bool IDictionary<TKey, TValue>.TryGetValue(TKey key, out TValue value) { lock (this.SyncRoot) { return this.TryGetValueCore(key, out value); } }
	}
}
